// 执行器

interface Config {
    id: string // 流 ID
    getFlowData: (id: string) => Promise<any> // 获取流数据 [cells]
    context?: any // 初始的上下文
    changeStatus?: (id: string, status: "stop" | "runing" | "success" | "error" | "failed" | "paused") => void;
}

interface Cell {
    id: string
    name: string
    shape: string
}

interface Node extends Cell {
    parent?: string

}

interface Edge extends Cell {
    name: 'edge'
    source: { cell: string, port: string }
    target: { cell: string, port: string }

}

interface FormData extends Record<string, Record<string, any>> { }


const ExtKeys = ["this", "true", "false", "class"];
const REG_EXP = /\{\{\s*(.*?)\s*\}\}/g;

export default class Executor {
    constructor(config: Config) {
        this.rootId = config.id;
        this.context = config.context;
        this.getFlowData = config.getFlowData;
        this.changeStatus = config.changeStatus;
        this.init()
    }


    rootId: string // 流的 根 ID
    context: Record<string, any> // 初始的上下文
    getFlowData: (id: string) => Promise<any>; // 依据 流 ID 获取 流数据
    changeStatus: ((id: string, status: "stop" | "runing" | "success" | "error" | "failed" | "paused") => void) | undefined; // 改变元素的状态   停止/运行中/运行成功/异常/运行失败/暂停
    //
    nodes: Node[] = [] // 节点集合
    edges: Edge[] = [] // 边集合
    data: FormData = {} // 元素的配置数据
    startNodes: Record<string, string[]> = { root: [] } // 开始节点集合
    nodeEdges = new Map<string, Edge[]>()
    names = new Map<string, string>()

    //
    /**
     * 初始化 获取 流数据 解析 流数据
     * 
     */
    async init() {
        const res = await this.getFlowData(this.rootId);
        const { nodes = [], edges = [], data } = res; //
        //
        this.nodes = nodes;
        this.edges = edges;
        const tn = new Set()
        //
        for (const e of this.edges) {
            tn.add(e.target.cell)
            const sn = e.source.cell;
            if (!this.nodeEdges.has(sn)) {
                this.nodeEdges.set(sn, [])
            }
            this.nodeEdges.get(sn)?.push(e)
        }
        for (const n of this.nodes) {
            this.names.set(n.id, n.name || n.shape)
            if (!tn.has(n.id)) {
                const k = n.parent || 'root'
                if (!this.startNodes[k]) {
                    this.startNodes[k] = []
                }
                this.startNodes[k].push(n.id)
            }
        }
        //
        if (data) {
            this.data = data;
        }

    }

    /**
     * 获取元素的表单数据
     */
    getCellData(id: string) {
        return this.data[id] || {};
    }

    /**
     * 运行
     */
    run() {
        for (const id of this.startNodes.root) {
            // 执行
            const ctx = this.createContext(this.context);
            // 执行
            // this.Cells.run(id, ctx);
        }
    }

    /**
     * 运行一个子流程
     * @param id 起始点 ID
     * @param ctx 上下文
     */
    runSub(id: string, ctx?: any) {
        // 获取 子流程 ID

    }

    /**
     * 获取上下文
     */

    /**
     * 获取流 数据 这个方法还是由外部传入比较好
     */


    /**
     * 算子是否可用  算子是否禁用了
     */
    isCellOK() { }

    /**
     * 获取元素的配置数据
     * @param id 元素 ID
     */
    cellData(id: string) { }

    /**
     * 获取节点所有的出边
     * 
     */
    outEdges(id: string) { }


    /**
     * 获取下一个节点 ID
     * @param eid 边的 id
     */
    nextNode(eid: string) { }

    /**
     * 查找启动节点
     */
    getStartNode(list: Edge[], parent?: string) {

    }

    /**
     * 创建一个新的上下文
     */
    createContext(ctx: any = {}, def: any = {}) {
        return Object.assign({}, ctx, def)
    }

    /**
     * 执行字符串表达式
     */
    eval(s = "", ctx: Record<string,any> = {}) {
        // 剔除不能作为 key 值的 字符串 如 onUpdate:XXX
        const keys = Object.keys(ctx)
            .filter((k) => typeof k === "string")
            .filter((k) => !ExtKeys.includes(k))
            .filter((k) => !/[^\w$]/.test(k));
        const vals = keys.map((k) => ctx[k]);
        const str = "return " + s;
        try {
            return new Function(...keys, str)(...vals);
        } catch (e) {
            console.error("字符串表达式执行异常！", s, ctx);
            console.error(keys, vals, str);
            console.error(e);
        }
        return undefined;
    }

    /**
     * 解析字符串模板
     */
    template(s = '',ctx: Record<string,any> = {}){
        if (!s) {
            return "";
        }
        let result: any[] = [];
        let res = s;
        let t;
        while((t = REG_EXP.exec(s)) != null){
            const [x, exp] = t;
            try {
                const v = this.eval(exp, ctx);
                if (typeof v === 'object') {
                    result = result.concat(v)
                } else {
                    res = res.replace(x, v);
                }
            } catch (e) {
                console.error("=====字符串模板解析异常！=====", exp, ctx);
            }
        }
        if (res != s || result.length == 0) {
            result.push(res)
        }
        return result;
    }

}